package com.usefullc.crawler.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.usefullc.common.enums.YesNoEnum;
import com.usefullc.common.exception.BizException;
import com.usefullc.common.util.BeanUtils;
import com.usefullc.common.util.JsonUtil;
import com.usefullc.common.util.RequestUtils;
import com.usefullc.common.util.http.HttpNewUtils;
import com.usefullc.common.util.http.RequestRes;
import com.usefullc.common.util.http.ResponseRes;
import com.usefullc.common.util.secure.Base64;
import com.usefullc.crawler.component.ExcelGenerator;
import com.usefullc.crawler.domain.*;
import com.usefullc.crawler.enums.ActiveInstanceStatusEnum;
import com.usefullc.crawler.enums.OutputTemplateTypeEnum;
import com.usefullc.crawler.enums.ProcessStatusEnum;
import com.usefullc.crawler.enums.SampleTypeEnum;
import com.usefullc.crawler.mapper.TemplateMapper;
import com.usefullc.crawler.param.ClientTaskSubmitParam;
import com.usefullc.crawler.param.ExportDataParam;
import com.usefullc.crawler.param.TemplateParam;
import com.usefullc.crawler.query.*;
import com.usefullc.crawler.vo.ClientActiveProcessTaskVo;
import com.usefullc.crawler.vo.ClientResultVo;
import com.usefullc.crawler.vo.ClientTaskVo;
import com.usefullc.crawler.vo.ExportTemplateVo;
import com.usefullc.system.entity.Pager;
import com.usefullc.system.entity.WebResult;
import com.usefullc.system.service.AbstractBizService;
import com.usefullc.system.service.SerialNumberService;
import com.usefullc.user.service.component.UserManager;
import com.usefullc.user.vo.UserVo;
import net.bytebuddy.asm.Advice;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 爬虫模板服务类
 *
 * @author: 星空
 * @date: 2022-07-26
 */
@Service
public class ClientTaskService extends AbstractBizService<TemplateMapper, Template, TemplateQuery> {

    @Autowired
    private SerialNumberService serialNumberService;

    @Autowired
    private ActiveService activeService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    private ActiveProcessService activeProcessService;

    @Autowired
    private OutputTemplateService outputTemplateService;

    @Autowired
    private ActiveInstanceService activeInstanceService;

    @Autowired
    private ActiveMainInstanceService activeMainInstanceService;

    @Value("${usefullc.cralwer.server_rpc_url}")
    private String serverRpcUrl;

//    @Value("${usefullc.cralwer.client_collect_url}")
//    private String crawlerUrl;

    @Value("${usefullc.cralwer.model}")
    private String crawlerModel;

    @Override
    protected QueryWrapper<Template> getQueryWrapper(TemplateQuery query) {
        QueryWrapper<Template> queryWrapper = super.getQueryWrapper(query);
        return queryWrapper;
    }

    public Pager<ClientTaskVo> findClientTaskByPage(TemplateQuery query) {
        Pager<Template> page = templateService.findByPage(query);
        Pager<ClientTaskVo> newPage = new Pager<>(page);
        List<Template> dataList = page.getDataList();
        List<ClientTaskVo> newDataList = new ArrayList<>();
        newPage.setDataList(newDataList);
        for (Template template : dataList) {
            //获取最后一次运行的活动实例
            ActiveProcessQuery activeProcessQuery = new ActiveProcessQuery();
            activeProcessQuery.setTemplateId(template.getId());
            activeProcessQuery.setResultLimit(1);
            ActiveProcess lastActiveProcess = activeProcessService.findOne(activeProcessQuery);
            ClientTaskVo clientTaskVo = BeanUtils.beanCopy(template, ClientTaskVo.class);
            clientTaskVo.setLastActiveProcess(lastActiveProcess);
            newDataList.add(clientTaskVo);
        }
        return newPage;
    }

//    public WebResult<List<Template>> getRpcTemplateList(TemplateQuery query) {
//        String reqUrl = serverRpcUrl + "/crawler/template/listAll";
//        Map<String, String> headersMap = new HashMap<>();
//        HttpServletRequest request = RequestUtils.getRequest();
//        String token = request.getHeader("token");
//        headersMap.put("token", token);
//        ResponseRes responseRes = HttpNewUtils.get(reqUrl, headersMap);
//        logger.info("http template  finished! responseRes={}", responseRes);
//        WebResult<List<Template>> webResult = JsonUtil.json2Bean(responseRes.getBodyText(), new TypeReference<WebResult<List<Template>>>() {
//        }); //JsonUtil.json2Bean(responseRes.getBodyText(),WebResult.class);
//        return webResult;
//    }

    public ExportTemplateVo getExportTemplate(Long templateId) {
        Template template = templateService.findById(templateId);

        Long copyTemplateId = template.getCopyTemplateId();
        OutputTemplateQuery oTemplateQuery = new OutputTemplateQuery();
        oTemplateQuery.setTemplateId(copyTemplateId);
        List<OutputTemplate> publicOutputTemplateList = outputTemplateService.findAll(oTemplateQuery);
//        //从远程获取模版
//        String reqUrl = serverRpcUrl + "/crawler/outputTemplate/listAll?templateId=" + copyTemplateId;
//        HttpServletRequest request = RequestUtils.getRequest();
//        String token = request.getHeader("token");
//        Map<String, String> headersMap = new HashMap<>();
//        headersMap.put("token", token);
//        ResponseRes responseRes = HttpNewUtils.get(reqUrl, headersMap);
//        logger.info("http get outputTemplate  finished!copyTemplateId={}, responseRes={}", copyTemplateId, responseRes);
//
//        WebResult<List<OutputTemplate>> webResult = JsonUtil.json2Bean(responseRes.getBodyText(), new TypeReference<WebResult<List<OutputTemplate>>>() {
//        });
//        if (!webResult.isSuccess()) {
//            throw new BizException(webResult.getMessage());
//        }
//        List<OutputTemplate> publicOutputTemplateList = webResult.getData();

        //从本地获取模版
        OutputTemplateQuery outputTemplateQuery = new OutputTemplateQuery();
        outputTemplateQuery.setTemplateId(templateId);
        List<OutputTemplate> dataList = outputTemplateService.findAll(outputTemplateQuery);

        OutputTemplate excelTemplate = null;
        OutputTemplate jdbcTemplate = null;
        OutputTemplate httpTemplate = null;
        for (OutputTemplate outputTemplate : dataList) {
            if (outputTemplate.getType().equals(OutputTemplateTypeEnum.EXCEL.getCode())) {
                excelTemplate = outputTemplate;
            } else if (outputTemplate.getType().equals(OutputTemplateTypeEnum.JDBC.getCode())) {
                jdbcTemplate = outputTemplate;
            }
            if (outputTemplate.getType().equals(OutputTemplateTypeEnum.HTTP.getCode())) {
                httpTemplate = outputTemplate;
            }
        }
        ExportTemplateVo exportTemplateVo = new ExportTemplateVo();

        for (OutputTemplate rpcOutputTemplate : publicOutputTemplateList) {
            if (rpcOutputTemplate.getType().equals(OutputTemplateTypeEnum.EXCEL.getCode())) {
                excelTemplate = BeanUtils.beanCopy(excelTemplate, rpcOutputTemplate);

            } else if (rpcOutputTemplate.getType().equals(OutputTemplateTypeEnum.JDBC.getCode())) {
                jdbcTemplate = BeanUtils.beanCopy(jdbcTemplate, rpcOutputTemplate);

            }
            if (rpcOutputTemplate.getType().equals(OutputTemplateTypeEnum.HTTP.getCode())) {
                httpTemplate = BeanUtils.beanCopy(httpTemplate, rpcOutputTemplate);
            }
        }
        exportTemplateVo.setExcelTemplate(excelTemplate);
        exportTemplateVo.setJdbcTemplate(jdbcTemplate);
        exportTemplateVo.setHttpTemplate(httpTemplate);

        return exportTemplateVo;
    }


    public ClientResultVo exportData(ExportDataParam param) {
        //先保存导出参数
        saveExportParam(param);

        if (StringUtils.equalsAnyIgnoreCase(crawlerModel, "client")) {
//            //给客户端发消息
//            RequestRes requestRes = new RequestRes();
//            requestRes.setMethod("POST");
////                requestRes.setHeaders(headerMap);
//            requestRes.setUrl(crawlerUrl + "exportData");
            String filterCondition = param.getFilterCondition();
            String fieldsCheckedConfig = param.getExcelTemplate().getFieldsCheckedConfig();
            String fieldsConfig = param.getExcelTemplate().getFieldsConfig();
//            requestRes.setParamText("{\"activeProcessId\":" + param.getActiveProcessId() + ",\"exportPart\":"+param.getExportPart()+",\"filterCondition\":\""+filterCondition+"\",\"fieldsCheckedConfig\":\""+fieldsCheckedConfig+"\"}");
////            requestRes.setParamText(JsonUtil.bean2Json(clientActiveProcessTaskVo));
//            ResponseRes responseRes = HttpNewUtils.execute(requestRes);
//            logger.info("http exportData  finished!activeProcessId={}, responseRes={}", param.getActiveProcessId() , responseRes);

            ClientResultVo clientResultVo = new ClientResultVo();
            clientResultVo.setActiveProcessId(param.getActiveProcessId());
            clientResultVo.setTemplateId(param.getTemplateId());
            clientResultVo.setExportDirPath(param.getExcelTemplate().getUrl());
            clientResultVo.setExportPart(param.getExportPart());
            clientResultVo.setFilterCondition(filterCondition);
            clientResultVo.setFieldsConfig(fieldsConfig);
            clientResultVo.setFieldsCheckedConfig(fieldsCheckedConfig);

            return clientResultVo;
        }else{
            Integer exportPart = param.getExportPart();
            String exportType = param.getExportType();
            Long templateId = param.getTemplateId();

            Template template = templateService.findById(templateId);

            List<String> resultDataLis = new ArrayList<>();
            //获取最后一个活动
            ActiveQuery activeQuery = new ActiveQuery();
            activeQuery.setStatus(YesNoEnum.YES.getCode());
            activeQuery.setTemplateId(templateId);
            activeQuery.setOrderByColumn("orderNo");
            activeQuery.setAscOrDesc("desc");
            activeQuery.setResultLimit(1);
            Active active = activeService.findOne(activeQuery);
            if (exportPart == 0) {  //全部导出
                //获取所有流程活动实例最后一个成功的活动实例列表
                ActiveInstanceQuery activeInstanceQuery = new ActiveInstanceQuery();
                activeInstanceQuery.setActiveId(active.getId());
                activeInstanceQuery.setStatus(ActiveInstanceStatusEnum.SUCCESS.getCode());
                List<ActiveInstance> activeInstanceList = activeInstanceService.findAllAnalyseDataList(activeInstanceQuery);
                for (ActiveInstance activeInstance : activeInstanceList) {
                    String responseAnalyseBody = activeInstance.getResponseAnalyseBody();
                    if (StringUtils.isNotEmpty(responseAnalyseBody)) {
                        resultDataLis.add(responseAnalyseBody);
                    }
                }

            } else {  //按活动实例导出

                Long activeProcessId = param.getActiveProcessId();
//            ActiveProcess activeProcess = activeProcessService.findById(activeProcessId);

                //获取该流程活动实例最后一个成功的活动实例列表
                ActiveInstanceQuery activeInstanceQuery = new ActiveInstanceQuery();
                activeInstanceQuery.setActiveId(active.getId());
                activeInstanceQuery.setActiveProcessId(activeProcessId);
                activeInstanceQuery.setStatus(ActiveInstanceStatusEnum.SUCCESS.getCode());
                List<ActiveInstance> activeInstanceList = activeInstanceService.findAllAnalyseDataList(activeInstanceQuery);
                for (ActiveInstance activeInstance : activeInstanceList) {
                    String responseAnalyseBody = activeInstance.getResponseAnalyseBody();
                    if (StringUtils.isNotEmpty(responseAnalyseBody)) {
                        resultDataLis.add(responseAnalyseBody);
                    }
                }

            }


            if (exportType.equals(OutputTemplateTypeEnum.EXCEL.getCode())) {
                OutputTemplate excelTemplate = param.getExcelTemplate();

                exportByExcel(template.getName(), excelTemplate.getUrl(), excelTemplate.getFieldsConfig(), excelTemplate.getFieldsCheckedConfig(), excelTemplate.getFilterCondition(), resultDataLis);

            } else if (exportType.equals(OutputTemplateTypeEnum.JDBC.getCode())) {

            } else if (exportType.equals(OutputTemplateTypeEnum.HTTP.getCode())) {

            }
        }
        return null;


    }


    private void saveExportParam(ExportDataParam param) {
        OutputTemplate excelTemplate = param.getExcelTemplate();
        OutputTemplate jdbcTemplate = param.getJdbcTemplate();
        OutputTemplate httpTemplate = param.getHttpTemplate();
        Long templateId = param.getTemplateId();
        excelTemplate.setTemplateId(templateId);
        outputTemplateService.save(excelTemplate);
        if (jdbcTemplate != null && StringUtils.isNotEmpty(jdbcTemplate.getName())) {
            jdbcTemplate.setTemplateId(templateId);
            outputTemplateService.save(jdbcTemplate);
        }
        if (httpTemplate != null && StringUtils.isNotEmpty(httpTemplate.getName())) {
            httpTemplate.setTemplateId(templateId);
            outputTemplateService.save(httpTemplate);
        }


    }

    private void exportByExcel(String fileName, String filePath, String columns, String checkedColumns, String filterCondition, List<String> resultDataList) {
        List<String> headerList = new ArrayList<>();
        JSONArray columnArray = JSONArray.parseArray(columns);
        List<String> checkedColumnArray = JsonUtil.json2Bean(checkedColumns, new TypeReference<List<String>>() {
        });
        for (String checkedColumn : checkedColumnArray) {
            for (int i = 0; i < columnArray.size(); i++) {
                JSONObject jsonObject = columnArray.getJSONObject(i);
                if (jsonObject.getString("value").equals(checkedColumn)) {
                    headerList.add(jsonObject.getString("label"));
                    break;
                }
            }
        }
        String headers = StringUtils.join(headerList, ",");
        List<String> allColumnList = new ArrayList<>();
        for (int i = 0; i < columnArray.size(); i++) {
            JSONObject jsonObject = columnArray.getJSONObject(i);
            allColumnList.add(jsonObject.getString("value"));
        }

        //filter
        List<Map<String, String>> conditionMapList = JsonUtil.json2Bean(filterCondition, new TypeReference<List<Map<String, String>>>() {
        });

        Map<String, List<String>> uniqueMap = new HashMap<>();

        List<List<String>> dataList = new ArrayList<>();
        //数据
        for (String resultData : resultDataList) {
            JSONArray jsonArray = JSON.parseArray(resultData);
            if (jsonArray.get(0) instanceof JSONArray) {
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONArray childJsonArray = jsonArray.getJSONArray(i);
                    List<String> itemList = new ArrayList<>();
                    for (int j = 0; j < childJsonArray.size(); j++) {
                        JSONObject jsonObject = childJsonArray.getJSONObject(j);
                        for (String column : allColumnList) {
                            Object value = jsonObject.get(column);
                            itemList.add(ObjectUtils.defaultIfNull(value, "").toString());
                        }
                        boolean match = matchItemList(allColumnList, itemList, conditionMapList, uniqueMap);
                        if (match) {
                            itemList.clear();
                            for (String column : checkedColumnArray) {
                                Object value = jsonObject.get(column);
                                itemList.add(ObjectUtils.defaultIfNull(value, "").toString());
                            }
                            dataList.add(itemList);
                        }
                    }
                }
            } else {
                for (int j = 0; j < jsonArray.size(); j++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(j);
                    List<String> itemList = new ArrayList<>();
                    for (String column : allColumnList) {
                        Object value = jsonObject.get(column);
                        itemList.add(ObjectUtils.defaultIfNull(value, "").toString());
                    }
                    boolean match = matchItemList(allColumnList, itemList, conditionMapList, uniqueMap);
                    if (match) {
                        itemList.clear();
                        for (String column : checkedColumnArray) {
                            Object value = jsonObject.get(column);
                            itemList.add(ObjectUtils.defaultIfNull(value, "").toString());
                        }
                        dataList.add(itemList);
                    }
                }
            }
        }


        //输出流
        ExcelGenerator.write(fileName, filePath, headers, dataList);

    }

    private boolean matchItemList(List<String> allColumnList, List<String> itemList, List<Map<String, String>> conditionMapList, Map<String, List<String>> uniqueMap) {
        for (Map<String, String> conditionMap : conditionMapList) {
            String name = conditionMap.get("name");
            int index = allColumnList.indexOf(name);
            String itemValue = itemList.get(index);

            String operator = conditionMap.get("operator");
            String value = conditionMap.get("value");
            if (operator.equals("required")) {
                if (StringUtils.isEmpty(itemValue)) {
                    return false;
                }
            } else if (operator.equals("unique")) {
                List<String> uniqueList = uniqueMap.get(name);
                if (CollectionUtils.isEmpty(uniqueList)) {
                    uniqueList = new ArrayList<>();
                    uniqueMap.put(name, uniqueList);
                }
                if (uniqueList.contains(itemValue)) {
                    return false;
                } else {
                    uniqueList.add(itemValue);
                }


            } else if (operator.equals("range")) {
                double numberValue = Double.parseDouble(itemValue); // 将字符串转换为 double
                String[] valueArray = value.split(",");
                String min = valueArray[0];
                String max = valueArray[1];
                if (StringUtils.isNoneBlank(min)) {
                    if (numberValue < Double.parseDouble(min)) {
                        return false;
                    }
                }
                if (StringUtils.isNoneBlank(max)) {
                    if (numberValue > Double.parseDouble(max)) {
                        return false;
                    }
                }
            } else if (operator.equals("equals")) {
                if (!StringUtils.equalsAnyIgnoreCase(value, itemValue)) {
                    return false;
                }

            } else if (operator.equals("not")) {
                if (StringUtils.equalsAnyIgnoreCase(value, itemValue)) {
                    return false;
                }
            } else if (operator.equals("prefix")) {
                if (!StringUtils.startsWithIgnoreCase(itemValue, value)) {
                    return false;
                }

            } else if (operator.equals("suffix")) {
                if (!StringUtils.endsWithIgnoreCase(itemValue, value)) {
                    return false;
                }

            } else if (operator.equals("wildcard")) {
                // 定义通配符模式
//                String wildcardPattern = ".*world.*";  // 匹配包含 "world" 的字符串
                // 创建正则表达式模式
                Pattern pattern = Pattern.compile(value);
                // 要检查的字符串
//                String inputString = "Hello, world!";
                // 创建匹配器
                Matcher matcher = pattern.matcher(itemValue);
                // 执行匹配
                if (!matcher.matches()) {
                    return false;
                }

            }
        }
        return true;
    }

    @Transactional
    public boolean saveClientTemplate(TemplateParam param) {
        param.setType(YesNoEnum.YES.getCode());
        //获取引用模版
        Long copyTemplateId = param.getCopyTemplateId();

        //如果用户已经创建了该模版任务，则无需创建
        TemplateQuery templateQuery = new TemplateQuery();
        templateQuery.setCopyTemplateId(copyTemplateId);
        UserVo loginUser = UserManager.getLoginUser();
        templateQuery.setUserId(loginUser.getId());
        long copyTemplateCount = templateService.count(templateQuery);
        if(copyTemplateCount > 0){
            throw new BizException("您已引用了该模版，无需再创建，请在[我的任务]中使用");
        }

        Template copyTemplate = templateService.findById(copyTemplateId);


//        String reqUrl = serverRpcUrl + "/crawler/template/detail?id=" + copyTemplateId;
//        HttpServletRequest request = RequestUtils.getRequest();
//        String token = request.getHeader("token");
//        Map<String, String> headersMap = new HashMap<>();
//        headersMap.put("token", token);
//        ResponseRes responseRes = HttpNewUtils.get(reqUrl, headersMap);
//        logger.info("http template  finished!copyTemplateId={}, responseRes={}", copyTemplateId, responseRes);
//        WebResult<Template> webResult = JsonUtil.json2Bean(responseRes.getBodyText(), new TypeReference<WebResult<Template>>() {
//        });
//        if (!webResult.isSuccess()) {
//            throw new BizException(webResult.getMessage());
//        }
//        Template copyTemplate = webResult.getData();
        String variables = param.getVariables();
        BeanUtils.beanCopy(param, copyTemplate);
        copyTemplate.setId(null);
        copyTemplate.setVariables(variables);
        copyTemplate.setUserId(loginUser.getId());

        templateService.save(copyTemplate);
        Long templateId = copyTemplate.getId();

        //获取引用活动
        ActiveQuery activeQuery = new ActiveQuery();
        activeQuery.setTemplateId(copyTemplateId);
        List<Active> activeList = activeService.findAll(activeQuery);
        for (Active active : activeList) {
            active.setTemplateId(templateId);
            active.setId(null);
        }

        return activeService.saveEntityList(activeList);
    }


    public boolean updateClientTemplate(TemplateParam param) {
        param.setType(YesNoEnum.YES.getCode());
        Template oldBean = templateService.findById(param.getId());
        BeanUtils.beanCopy(param, oldBean);
        templateService.update(oldBean);

        //修改活动
        ActiveQuery activeQuery = new ActiveQuery();
        activeQuery.setTemplateId(param.getId());
        List<Active> activeList = activeService.findAll(activeQuery);
        return activeService.saveEntityList(activeList);
    }


    public void copy(Long id) {
        Template template = this.findById(id);
        template.setId(null);
        template.setName(template.getName() + "_copy");
        this.save(template);
    }


    @Transactional
    public ClientResultVo submit(ClientTaskSubmitParam param) {
        Long activeProcessId = param.getActiveProcessId();

        ActiveMainInstanceQuery activeMainInstanceQuery = new ActiveMainInstanceQuery();
        activeMainInstanceQuery.setActiveProcessId(activeProcessId);
        activeMainInstanceQuery.setStatus(YesNoEnum.NO.getCode());
        activeMainInstanceQuery.setResultLimit(1);
        ActiveMainInstance currentActiveMainInstance = activeMainInstanceService.findOne(activeMainInstanceQuery);

        List<ActiveInstance> taskDataList = param.getTaskDataList();
        List<ActiveInstance> newTaskDataList = new ArrayList<>();
        long successNum = taskDataList.stream().filter(data -> data.getStatus() == YesNoEnum.YES.getCode()).count();
        long failedNum = taskDataList.stream().filter(data -> data.getStatus() == YesNoEnum.NO.getCode()).count();
        for (ActiveInstance activeInstance : taskDataList) {
//            if (activeInstance.getStatus() == YesNoEnum.NO.getCode()) {
//                continue;
//            }
            String responseAnalyseBody = activeInstance.getResponseAnalyseBody();
            if (StringUtils.isBlank(responseAnalyseBody)) {
               continue;
            }
            if(responseAnalyseBody.matches("^\\[.*\\]$")){
                List<String> resAnalyseBodyList = JsonUtil.json2List(responseAnalyseBody, String.class);
                for (String resAnalyseBody : resAnalyseBodyList) {
                    byte[] decode = Base64.decode(resAnalyseBody);
                    String str = new String(decode);
                    Object obj = JSONObject.parse(str);
                    ActiveInstance newActiveInstance = new ActiveInstance();
                    newActiveInstance.setStatus(YesNoEnum.YES.getCode());
                    newActiveInstance.setResponseAnalyseBody(obj.toString());
                    newTaskDataList.add(newActiveInstance);
                }

            }else{
                byte[] decode = Base64.decode(responseAnalyseBody);
                String str = new String(decode);
                Object obj = JSONObject.parse(str);
                activeInstance.setStatus(YesNoEnum.YES.getCode());
                activeInstance.setResponseAnalyseBody(obj.toString());
                newTaskDataList.add(activeInstance);
            }
        }
////        ActiveMainInstance activeMainInstance = activeMainInstanceList.get(0);
//        Long activeMainInstanceId = activeMainInstance.getId();
//        ActiveInstanceQuery activeInstanceQuery = new ActiveInstanceQuery();
//        activeInstanceQuery.setActiveMainInstanceId(activeMainInstanceId);
//        activeInstanceQuery.setStatus(ActiveInstanceStatusEnum.SUCCESS.getCode());
//        long successNum = activeInstanceService.count(activeInstanceQuery);
//
//        activeInstanceQuery.setStatus(ActiveInstanceStatusEnum.FAILED.getCode());
//        long failedNum = activeInstanceService.count(activeInstanceQuery);

        currentActiveMainInstance.setSuccessNum((int) successNum);
        currentActiveMainInstance.setFailNum((int) failedNum);
        currentActiveMainInstance.setStatus(YesNoEnum.YES.getCode());
        activeMainInstanceService.save(currentActiveMainInstance);  //保存


//        ActiveQuery activeQuery1 = new ActiveQuery();l12
        Active currentActive = activeService.findById(currentActiveMainInstance.getActiveId());


        ActiveQuery activeQuery = new ActiveQuery();
        activeQuery.setTemplateId(currentActive.getTemplateId());
        activeQuery.setStatus(YesNoEnum.YES.getCode());
        activeQuery.setOrderNo(currentActive.getOrderNo() + 1);
        Active active = this.activeService.findOne(activeQuery);

        activeQuery = new ActiveQuery();
        activeQuery.setTemplateId(currentActive.getTemplateId());
        activeQuery.setStatus(YesNoEnum.YES.getCode());
        activeQuery.setOrderNoGt(active.getOrderNo());
        long activeCount = activeService.count(activeQuery);
        Integer hasNextActive = activeCount > 0 ? 1 : 0;


        Long activeId = active.getId();
        logger.info("start active activeProcessId={},prevActiveId={},currentActiveId={}", activeProcessId, currentActive.getId(), activeId);
        Long templateId = active.getTemplateId();
        Template template = templateService.findById(templateId);
        String variables = template.getVariables();
        Map<String, String> variableMap = JsonUtil.json2Map(variables);

//        List<ActiveInstance> activeInstanceList = new ArrayList<>();
        List<String> reqUrls = activeProcessService.analyseUrl(active.getUrl(), activeProcessId, currentActive.getId(), variableMap, newTaskDataList);

        //url 去重
        reqUrls = new ArrayList<>(new LinkedHashSet<>(reqUrls));

        int totalNum = reqUrls.size();
        int beforeSampleTotalNum = totalNum;
        //抽样处理
        Integer sampleValue = template.getSampleValue();
        if (template.getSampleType() == SampleTypeEnum.NUMERAL.getCode()) {
            totalNum = NumberUtils.min(sampleValue, totalNum);
        } else {
            BigDecimal divide = BigDecimal.valueOf(totalNum).multiply(BigDecimal.valueOf(sampleValue)).divide(BigDecimal.valueOf(100), RoundingMode.HALF_UP);
            totalNum = divide.intValue();
        }
        reqUrls = reqUrls.subList(0, totalNum);
        logger.info("before sample num={},after num={}", beforeSampleTotalNum, totalNum);


        //主活动实例
        ActiveMainInstance activeMainInstance = new ActiveMainInstance();
        activeMainInstance.setTemplateId(templateId);
        activeMainInstance.setStatus(ProcessStatusEnum.RUNNING.getCode());
        activeMainInstance.setActiveId(activeId);
        activeMainInstance.setName(active.getName());
        activeMainInstance.setActiveProcessId(activeProcessId);
        activeMainInstance.setTotalNum(totalNum);
        activeMainInstance.setSuccessNum(0);
        activeMainInstance.setFailNum(0);
        activeMainInstanceService.save(activeMainInstance);
//        Long mainActiveInstanceId = activeMainInstance.getId();

        //构建客户端任务实例，发送到客户端
        ClientActiveProcessTaskVo clientActiveProcessTaskVo = new ClientActiveProcessTaskVo();
        clientActiveProcessTaskVo.setHasNextActive(hasNextActive);
        clientActiveProcessTaskVo.setMethod(active.getMethod());
        clientActiveProcessTaskVo.setRequestType(active.getRequestType());
        String cookie = active.getCookie();
        String requestHeaders = active.getRequestHeaders();
        if (StringUtils.isNoneBlank(cookie)) {
            HashMap<String, String> requestHeaderMap = JsonUtil.json2Map(requestHeaders);
            requestHeaderMap.put("cookie",cookie);
            requestHeaders = JsonUtil.map2Json(requestHeaderMap);
        }
        clientActiveProcessTaskVo.setRequestHeaders(requestHeaders);
        clientActiveProcessTaskVo.setRequestBody(active.getRequestBody());
        clientActiveProcessTaskVo.setActiveProcessId(activeProcessId);
        clientActiveProcessTaskVo.setTemplateId(active.getTemplateId());
        clientActiveProcessTaskVo.setName(template.getName());
        clientActiveProcessTaskVo.setActiveName(active.getName());
        clientActiveProcessTaskVo.setStorePageSource(0);
        clientActiveProcessTaskVo.setTimeRdMs(template.getRunRdMs());
        clientActiveProcessTaskVo.setActiveId(active.getId());
//                clientActiveProcessTaskVo.setActiveInstanceId(0L);
//                clientActiveProcessTaskVo.setActiveId(0L);
//                clientActiveProcessTaskVo.setCookie("");
//                clientActiveProcessTaskVo.setStartTime(0L);
        clientActiveProcessTaskVo.setAnalyseBanExpress(active.getAnalyseBanExpress());
        clientActiveProcessTaskVo.setAnalyseExpress(active.getAnalyseExpress());
        clientActiveProcessTaskVo.setAnalyseDataExpress(active.getAnalyseDataExpress());
//                clientActiveProcessTaskVo.setSwitchProxyExpress("");
        clientActiveProcessTaskVo.setExtractDataUrl(active.getExtractDataUrl());
        clientActiveProcessTaskVo.setSliceActive(active.getSliceActive());
        clientActiveProcessTaskVo.setWaitCssSelectorExpress(active.getWaitCssSelectorExpress());
        clientActiveProcessTaskVo.setDirtyCssSelectorExpress(active.getDirtyCssSelectorExpress());
        clientActiveProcessTaskVo.setUiEventScript(active.getUiEventScript());
        clientActiveProcessTaskVo.setAnalyseExpressType(active.getAnalyseExpressType());
        clientActiveProcessTaskVo.setVariables(template.getVariables());
        clientActiveProcessTaskVo.setRunTimeout(active.getRunTimeout());
        clientActiveProcessTaskVo.setUrls(reqUrls);

        ClientResultVo clientResultVo = new ClientResultVo();
        clientResultVo.setCreateWin(false);
        clientResultVo.setClientActiveProcessTaskVo(clientActiveProcessTaskVo);

        logger.info("client task submit finished,activeProcessId={},successNum={},failedNum={},urls size={}",activeProcessId,successNum,failedNum,reqUrls.size());

        return clientResultVo;
    }


    @Transactional
    public void submitLeaf(ClientTaskSubmitParam param) {
        Long activeProcessId = param.getActiveProcessId();

        ActiveMainInstanceQuery activeMainInstanceQuery = new ActiveMainInstanceQuery();
        activeMainInstanceQuery.setActiveProcessId(activeProcessId);
        activeMainInstanceQuery.setStatus(YesNoEnum.NO.getCode());
        activeMainInstanceQuery.setResultLimit(1);
        ActiveMainInstance currentActiveMainInstance = activeMainInstanceService.findOne(activeMainInstanceQuery);

//        List<ActiveInstance> taskDataList = param.getTaskDataList();
//        List<ActiveInstance> newTaskDataList = new ArrayList<>();
        long successNum = param.getSuccessNum();
        long failedNum = param.getFailedNum();


        currentActiveMainInstance.setSuccessNum((int) successNum);
        currentActiveMainInstance.setFailNum((int) failedNum);
        currentActiveMainInstance.setStatus(YesNoEnum.YES.getCode());
        activeMainInstanceService.save(currentActiveMainInstance);  //保存

        activeProcessService.success(activeProcessId);

        logger.info("client task submit leaf finished,activeProcessId={},successNum={},failedNum={}",activeProcessId,successNum,failedNum);

////        ActiveQuery activeQuery1 = new ActiveQuery();l12
//        Active currentActive = activeService.findById(currentActiveMainInstance.getActiveId());
//
//
//        ActiveQuery activeQuery = new ActiveQuery();
//        activeQuery.setTemplateId(currentActive.getTemplateId());
//        activeQuery.setStatus(YesNoEnum.YES.getCode());
//        activeQuery.setOrderNo(currentActive.getOrderNo() + 1);
//        Active active = this.activeService.findOne(activeQuery);
//
//        if (active == null) {
//            logger.info("activeProcess finished,activeProcessId={}", activeProcessId);
//            //完成后，修改状态为成功
//            activeProcessService.success(activeProcessId);
//            return;
//        }

    }

}
